package com.army.cookbook.slice;

import com.army.cookbook.MainAbility;
import com.army.cookbook.OpenCamera;
import com.army.cookbook.ResourceTable;
import com.army.cookbook.util.FaceAuthResult;
import com.army.cookbook.util.LogUtils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;
import ohos.biometrics.authentication.BiometricAuthentication;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MainAbilitySlice extends AbilitySlice {
    private static final int POOL_CORE_SIZE = 2;
    private static final int POOL_MAX_SIZE = 5;
    private static final int NO_FACE_RET = -1;
    private static final int KEEP_ALIVE_TIME = 3;
    private static final int QUEUE_SIZE = 6;
    private static final int RET_NOT_SUPPORTED = 1;
    private static final int RET_SAFE_LEVEL_NOT_SUPPORTED = 2;
    private static final int RET_NOT_LOCAL = 3;

    private EventRunner runner;
    private MyEventHandle myEventHandle;
    private BiometricAuthentication mBiometricAuthentication;

    /**
     * 新建线程进行认证，避免阻塞其他任务
     */
    private Runnable runnable = new Runnable() {
        private void initHandler() {
            runner = EventRunner.getMainEventRunner();
            if (runner == null) {
                return;
            }
            myEventHandle = new MyEventHandle(runner);
        }

        @Override
        public void run() {
            // 初始化myEventHandle
            initHandler();
            // 开始认证
            startAuth();
        }
    };

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        // 创建开始认证按钮，并添加点击事件
        createStartBtn();
        // 创建取消认证按钮，并添加点击事件
        createCancelBtn();
    }

    private void createCancelBtn() {
        // 创建点击事件
        Component component = findComponentById(ResourceTable.Id_button_cancel);
        // 创建按钮
        Button cancelBtn = null;
        if (component != null && component instanceof Button) {
            cancelBtn = (Button) component;
            cancelBtn.setClickedListener(view -> {
                if (mBiometricAuthentication != null) {
                    // 调用取消接口
                    int result = mBiometricAuthentication.cancelAuthenticationAction();
                    LogUtils.info("createCancelBtn:", result + "");
                    getAndSetText(ResourceTable.Id_text_status, 2, true);
                }
            });
        }
    }


    /**
     * 创建开始识别的按钮点击事件
     */
    private void createStartBtn() {
        // 创建点击事件
        Component component = findComponentById(ResourceTable.Id_button_start);
        // 创建按钮
        Button featureBtn = null;
        if (component != null && component instanceof Button) {
            featureBtn = (Button) component;
            featureBtn.setClickedListener(view -> {
                createStartListener();
            });
        }
    }

    private void createStartListener() {
        // 提示用户人脸识别时将人脸对准摄像头
        getAndSetText(ResourceTable.Id_text_status, NO_FACE_RET, true);
        try {
            // 创建生物识别对象
            mBiometricAuthentication = BiometricAuthentication.getInstance(MainAbility.getMainAbility());
            // 检验设备是否有人脸识别功能
            // BiometricAuthentication.AuthType中有三个类别
            // 分别为AUTH_TYPE_BIOMETRIC_FINGERPRINT_ONLY指纹识别
            // AUTH_TYPE_BIOMETRIC_FACE_ONLY脸部识别
            // AUTH_TYPE_BIOMETRIC_ALL指纹和面部
            // BiometricAuthentication.SecureLevel 2D人脸识别建议使用SECURE_LEVEL_S2，3D人脸识别建议使用SECURE_LEVEL_S3
            int hasAuth = mBiometricAuthentication.checkAuthenticationAvailability(
                    BiometricAuthentication.AuthType.AUTH_TYPE_BIOMETRIC_FACE_ONLY,
                    BiometricAuthentication.SecureLevel.SECURE_LEVEL_S2, true);

            // hasAuth 0是支持，1是不支持，2安全级别不支持 3不是本地认证 4无人脸录入
            if (hasAuth == BiometricAuthentication.BA_CHECK_SUPPORTED) {
                // 如果支持人脸识别，则开启线程进行人脸识别
                ThreadPoolExecutor pool = new ThreadPoolExecutor(
                        POOL_CORE_SIZE, POOL_MAX_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
                        new LinkedBlockingQueue<>(QUEUE_SIZE), new
                        ThreadPoolExecutor.DiscardOldestPolicy());
                pool.submit(runnable);
            } else {
                // 人脸识别不支持或存在其他问题 ，直接在页面显示结果，
                // 在主线程不需要通过EventHandler发送回显任务
                int retExcAuth = getRetExcAuth(hasAuth);
                getAndSetText(ResourceTable.Id_text_status, retExcAuth, true);
            }
        } catch (IllegalAccessException e) {
            LogUtils.error("createStartBtn", "IllegalAccessException when start auth");
        }
    }

    private void startAuth() {
        // retExcAuth 0认证成功 1：比对失败 2：取消认证 3：认证超时 4：打开相机失败
        // 5：busy，可能上一个认证没有结束 6：入参错误 7：人脸认证锁定（达到错误认证次数了)
        // 8：没有录入人脸 100:其他错误。
        int retExcAuth = mBiometricAuthentication.execAuthenticationAction(
                BiometricAuthentication.AuthType.AUTH_TYPE_BIOMETRIC_FACE_ONLY,
                BiometricAuthentication.SecureLevel.SECURE_LEVEL_S2,
                true, false, null);
        // 将认证结果发给主线程处理
        myEventHandle.sendEvent(retExcAuth);
    }

    /**
     * 根据检验是否支持认证返回值获取提示code
     *
     * @param hasAuth 是否有认证能力
     * @return 返回认证码
     */
    private int getRetExcAuth(int hasAuth) {
        int retExcAuth;
        if (hasAuth == RET_NOT_SUPPORTED) {
            // 1是不支持2D人脸识别
            retExcAuth = FaceAuthResult.AUTH_2D_NOT_SUPPORTED;
        } else if (hasAuth == RET_SAFE_LEVEL_NOT_SUPPORTED) {
            // 安全级别不支持
            retExcAuth = FaceAuthResult.AUTH_SAFE_LEVEL_NOT_SUPPORTED;
        } else if (hasAuth == RET_NOT_LOCAL) {
            // 是不是本地认证
            retExcAuth = FaceAuthResult.AUTH_NOT_LOCAL;
        } else {
            // 无人脸录入
            retExcAuth = FaceAuthResult.AUTH_NO_FACE;
        }
        return retExcAuth;
    }

    /**
     * 获取并设置text
     *
     * @param textId 文本框id
     * @param retExcAuth 认证返回码
     * @param isVisible 是否显示
     */
    private void getAndSetText(int textId, int retExcAuth, boolean isVisible) {
        // 获取状态Text
        Component componentText = findComponentById(textId);
        if (componentText != null && componentText instanceof Text) {
            Text text = (Text) componentText;
            setTextValueAndColor(retExcAuth, text);
            if (isVisible) {
                text.setVisibility(Component.VISIBLE);
            }
        }
    }

    /**
     * 设置文本提示信息
     *
     * @param text 文本对象
     * @param textValue 文本值
     * @param color 文本颜色
     */
    private void setTextValueAndColor(Text text, String textValue, Color color) {
        text.setText(textValue);
        text.setTextColor(color);
    }

    /**
     * 设置文本显示值和文本颜色
     *
     * @param retExcAuth 认证返回值
     * @param text 文本对象
     */
    private void setTextValueAndColor(int retExcAuth, Text text) {
        switch (retExcAuth) {
            case FaceAuthResult.AUTH_SUCCESS:
                setTextValueAndColor(text, "认证成功", Color.GREEN);
                // 页面跳转
                toAuthAfterPage();
                break;
            case FaceAuthResult.AUTH_FAIL:
                setTextValueAndColor(text, "比对失败", Color.RED);
                break;
            case FaceAuthResult.AUTH_CANCLE:
                setTextValueAndColor(text, "取消认证", Color.RED);
                break;
            case FaceAuthResult.AUTH_TIME_OUT:
                setTextValueAndColor(text, "认证超时", Color.RED);
                break;
            case FaceAuthResult.AUTH_OPEN_CAMERA_FAIL:
                setTextValueAndColor(text, "打开相机失败", Color.RED);
                break;
            case FaceAuthResult.AUTH_BUSY:
                setTextValueAndColor(text, "busy，可能上一个认证没有结束", Color.RED);
                break;
            case FaceAuthResult.AUTH_PARAM_ERROR:
                setTextValueAndColor(text, "入参错误", Color.RED);
                break;
            case FaceAuthResult.AUTH_FACE_LOCKED:
                setTextValueAndColor(text, "人脸认证锁定（达到错误认证次数了)", Color.RED);
                break;
            case FaceAuthResult.AUTH_NO_FACE:
                setTextValueAndColor(text, "无人脸录入,请录入人脸。", Color.BLUE);
                break;
            case FaceAuthResult.AUTH_OTHER_ERROR:
                setTextValueAndColor(text, "其他错误。", Color.RED);
                break;
            case FaceAuthResult.AUTH_2D_NOT_SUPPORTED:
                setTextValueAndColor(text, "不支持2D人脸识别。", Color.BLUE);
                break;
            case FaceAuthResult.AUTH_SAFE_LEVEL_NOT_SUPPORTED:
                setTextValueAndColor(text, "安全级别不支持。", Color.BLUE);
                break;
            case FaceAuthResult.AUTH_NOT_LOCAL:
                setTextValueAndColor(text, "不是本地认证。", Color.BLUE);
                break;
            default:
                setTextValueAndColor(text, "开始认证，请将视线对准摄像头。。。。。。。", Color.BLUE);
                break;
        }
    }

    private void toAuthAfterPage() {
        Intent secondIntent = new Intent();
        // 指定待启动FA的bundleName和abilityName
        Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(getBundleName())
                .withAbilityName(OpenCamera.class.getName())
                .build();
        secondIntent.setOperation(operation);
        // 通过AbilitySlice的startAbility接口实现启动另一个页面
        startAbility(secondIntent);
    }

    /**
     * 事件分发器
     */
    private class MyEventHandle extends EventHandler {
        MyEventHandle(EventRunner runner) throws IllegalArgumentException {
            super(runner);
        }

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            int eventId = event.eventId;
            getAndSetText(ResourceTable.Id_text_status, eventId, true);
        }
    }

    @Override
    public void onStop() {
        mBiometricAuthentication.cancelAuthenticationAction();
        BiometricAuthentication.AuthenticationTips authenticationTips
                = mBiometricAuthentication.getAuthenticationTips();
        String tips = authenticationTips.tipInfo;
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}
